import socket,copy
import xml.etree.ElementTree as et
from sys import platform, argv
from utils import Utilities
from listeners.sectorum import Sectorum
from random import choice
from random import random
from xmlrpc import client
from os import listdir, walk, system, chdir, _exit
from threading import Thread
from time import sleep
from http import client as clientHTTP

PID=0 # critical part of the script, don't touch
admins = [] # critical part of the script, don't touch

SRV_PATH = "C:/Users/Autumn/Documents/TMServer"

localRoot = et.parse(SRV_PATH+"/ilsc/RECORDS").getroot()
configRoot = et.parse(SRV_PATH+"/ilsc/CONFIG").getroot()
u = None

def displayManialinks(s,player=None):
	for (a,b,c) in walk(SRV_PATH+"/ilsc/panels"):
		for i in c:
			with open(SRV_PATH+"/ilsc/panels/"+i,"r") as f:
				if(player==None):
					u.sendMessage(client.dumps((f.read(),0,False),methodname="SendDisplayManialinkPage").encode(),s)
				else:
					u.sendMessage(client.dumps((player,f.read(),0,False),methodname="SendDisplayManialinkPageToLogin").encode(),s)
				f.close()

def eventLoop(socket):
	global admins, localRoot
	curChallName = ""
	while(1):
		try:
			try:
				try:
					data,method = u.listen()
				except Exception as e:
					if(str(e)=="cannot unpack non-iterable NoneType object"):
						pass
					else:
						print(e)
					continue
				if(method=="TrackMania.PlayerChat"):
					user,command,args = u.splitData(data,method)
					if(command==prefix+"echo"):
						u.adminMessage(user,admins,client.dumps((" ".join(args),),methodname="ChatSend").encode(),socket)
					if(command==prefix+"kick"):
						u.adminMessage(user,admins,client.dumps((args[0], " ".join(args[1:])),methodname="Kick").encode(),socket)
					if(command==prefix+"ban"):
						u.adminMessage(client.dumps((args[0], " ".join(args[1:]), True),methodname="BanAndBlackList").encode(),socket)
					if(command==prefix+"reloadAdmins"):
						if(u.adminMessage(user,admins,client.dumps(("Reloading admin list...",user),methodname="ChatSendToLogin").encode(),socket)):
							with open(SRV_PATH+"/ilsc/ADMINS","r") as f:
								admins = []
								for line in f:
									admins.append(line.strip("\n"))
							u.adminMessage(user,admins,client.dumps(("Done reloading admin list!",user),methodname="ChatSendToLogin").encode(),socket)
					if(command==prefix+"insertChallenge"):
						u.adminMessage(user,admins,client.dumps(("Challenges/"+args[0],),methodname="InsertChallenge").encode(),socket)
						u.adminMessage(user,admins,client.dumps(("Tracks.txt",),methodname="SaveMatchSettings").encode(),socket)
						u.adminMessage(user,admins,client.dumps(("Done inserting the challenge!",user),methodname="ChatSendToLogin").encode(),socket)
					if(command==prefix+"reloadMatchSettings"):
						u.adminMessage(user,admins,client.dumps(("Tracks.txt",),methodname="LoadMatchSettings").encode(),socket)
						u.adminMessage(user,admins,client.dumps(("Done reloading match settings!",user),methodname="ChatSendToLogin").encode(),socket)
					if(command==prefix+"restartChallenge"):
						u.adminMessage(user,admins,client.dumps(tuple(),methodname="RestartChallenge").encode(),socket)
						u.adminMessage(user,admins,client.dumps(("Admin "+user+" restarts the current challenge!",),methodname="ChatSend").encode(),socket)
					if(command==prefix+"skipToChallenge"):
						u.adminMessage(user,admins,client.dumps(("Challenges/"+args[0],),methodname="ChooseNextChallenge").encode(),socket)
						u.adminMessage(user,admins,client.dumps(("Admin "+user+" skips to another challenge!",),methodname="ChatSend").encode(),socket)
						u.adminMessage(user,admins,client.dumps(tuple(),methodname="NextChallenge").encode(),socket)
					if(command==prefix+"help"):
						u.sendMessage(client.dumps(('''.
ADMIN COMMANDS:
/echo: Echos whatever is sent. Sandboxed for privacy reasons.
/kick: Kicks the user provided.
/ban:  Bans the user provided.
/reloadAdmins: Reloads the ADMINS list in the server controller's directory.
/insertChallenge, /reloadMatchSettings: Used for inserting challenges and reloading match settings respectively, to help with your workflow of adding tracks minimalistically.
/restartChallenge: Restarts the current challenge.
/skipToChallenge: Used for skipping to the next challenge in the queue, or for skipping to a specific challenge as specified by /challenges.
USER COMMANDS:
/help: Displays this help text.
/challenges: Lists all challenges on disk.''',user),methodname="ChatSendToLogin").encode(),socket)
					if(command==prefix+"challenges"):
						for a,b,c in walk(SRV_PATH+"/GameData/Tracks/Challenges"):
							for name in c:
								u.sendMessage(client.dumps((name,user),methodname="ChatSendToLogin").encode(),socket)
					if(command==prefix+"lr"):
						u.sendMessage(client.dumps(("For challenge %s:"%curChallName,user),methodname="ChatSendToLogin").encode(),socket)
						times = []
						for c in localRoot:
							if c.attrib['name']==curChallName:
								for c1 in c:
									if c1.tag=='record':
										times.append(c1.text)
								times.sort(key=lambda t: int(t.split(":")[1]))
								break
						for t in times:
							u.sendMessage(client.dumps(("%s: %s"%(t.split(":")[0],u.msToHMS(t.split(":")[1])),user),methodname="ChatSendToLogin").encode(),socket)
				if(method=="TrackMania.PlayerConnect"):
					user = u.splitData(data,method)
					displayManialinks(socket,user)
					u.sendMessage(client.dumps(('''.
Welcome to Irohia's Lair!
Please type /help if you would like to have help using this server.
We aim to be extremely minimalistic, so you can focus on having fun.''',user),methodname="ChatSendToLogin").encode(),socket)
				if(method=="TrackMania.BeginChallenge"):
					curChallName = u.splitData(data,method)
				if(method=="TrackMania.EndChallenge"):
					musicTrack = choice(listdir(SRV_PATH+"/GameData/Songs"))
					u.sendMessage(client.dumps((True,"Songs/"+musicTrack),methodname="SetForcedMusic").encode(),socket)
				if(method=="TrackMania.PlayerFinish"):
					userName,time = u.splitData(data,method)
					if(userName!=serverName):
						endStr = userName+" finished with a time of "+u.msToHMS(time)+"!"
						if(not endStr[::-1].startswith("!s0.0")):
							u.sendMessage(client.dumps((endStr,),methodname="ChatSend").encode(),socket)
							setFlag = 0
							for c in localRoot:
								if c.attrib['name']==curChallName:
									for c1 in c:
										if c1.tag=='record':
											if str(c1.text.split(":")[0]) == userName:
												if int(c1.text.split(":")[1]) >= time:
													c1.text = userName+":"+str(time)
													setFlag = 1
												else:
													setFlag = 1
													break
											else:
												child = et.SubElement(c,'record')
												child.text = userName+":"+str(time)
												c.append(child)
												setFlag = 1
								else:
									continue
							if(setFlag!=1):
								child = et.Element('track')
								child.set('name',curChallName)
								subchild = et.SubElement(child,'record')
								subchild.text = userName+":"+str(time)
								localRoot.append(child)
								setFlag=0
			except Exception as e:
				continue
		except Exception as e:
			continue

def startServer():
	if platform=="linux" or platform=="linux2":
		system('bash -c "cd ../; ./TrackmaniaServer /internet /dedicated_cfg=dedicated_cfg.txt /game_settings=Tracks.txt /nodaemon"')
	elif platform=="win32":
		chdir('..\\')
		system('.\\TrackmaniaServer.exe /dedicated_cfg=dedicated_cfg.txt /game_settings=Tracks.txt /verbose_rpc_full')
	else:
		print("[FATAL] ilsc does not support this operating system. Please refer to the Docs. Shutting down now...")
		exit(1)

def dediAuth(commCode,socket):
	if commCode == 0:
		print('[INFO] Dedimania is not configured! Please change the communityCode value or refer to the Docs.')
		pass
	else:
		pass

if(argv[1]=="decrypt"):
	with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
		u = Utilities(s)
		for i in configRoot:
			globals()[i.tag] = i.text
		with open(SRV_PATH+"/ilsc/KEYFILE","rb") as k:
			with open(SRV_PATH+"/GameData/Config/dedicated_cfg.txt","r+b") as f:
				u.decryptFile(k,f)
		t = Thread(target=startServer)
		t.start()
		sleep(10)
		with open(SRV_PATH+"/GameData/Config/dedicated_cfg.txt", "r+b") as f:
			u.encryptFile(f,SRV_PATH+"/ilsc/KEYFILE")
		s.connect((host,int(port)))
		data = s.recv(4)
		size = int.from_bytes(data,'little')
		data = s.recv(size)
		if(data == "GBXRemote 2".encode()):
			try:
				with open(SRV_PATH+"/ilsc/ADMINS","r") as f:
					for line in f:
						admins.append(line.strip("\n"))
				u.sendMessage(client.dumps(("SuperAdmin",superAdmin_password),methodname="Authenticate").encode(),s)
				u.sendMessage(client.dumps((True,),methodname="EnableCallbacks").encode(),s)
				u.sendMessage(client.dumps(("ILSC v0.0.1 booting up...","",5),methodname="SendNotice").encode(),s)
				u.sendMessage(client.dumps(tuple(),methodname="RestartChallenge").encode(),s)
				dediAuth(int(communityCode),s)
				displayManialinks(s)
				u.registerListener(0)
				u.recvWorkThread.start()
				Sectorum().exec(u,prefix,s)
				eventLoop(s)
				s.close()
				exit(0)
			except KeyboardInterrupt as ki:
				xs = et.tostring(localRoot,encoding="unicode")
				with open(SRV_PATH+"/ilsc/RECORDS","r+") as f:
					f.seek(0)
					f.write(xs)
					f.truncate()
				s.close()
				_exit(0)
		else:
			print("[PANIC] Failed to get hello!")
			s.close()
			exit(1)
elif(argv[1]=="encrypt"):
	u = Utilities()
	with open(SRV_PATH+"/GameData/Config/dedicated_cfg.txt", "r+b") as f:
		u.encryptFile(f,SRV_PATH+"/ilsc/KEYFILE")
		print("Done! Store the KEYFILE offsite to provide more protection...")
		exit(0)